#include "widget_node_physical.h"
#include "ui_widget_node_physical.h"
#include <QMessageBox>
#include "../AvatarLibrary.h"

WidgetNodePhysical::WidgetNodePhysical(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::WidgetNodePhysical)
{
    ui->setupUi(this);
    QDoubleValidator* val1 = new QDoubleValidator(0, 9999, 3, this);
    QDoubleValidator* val2 = new QDoubleValidator(-1, 0, 3, this);
    QDoubleValidator* val3 = new QDoubleValidator(0, 1, 3, this);
    val1->setNotation(QDoubleValidator::StandardNotation);
    val2->setNotation(QDoubleValidator::StandardNotation);
    val3->setNotation(QDoubleValidator::StandardNotation);
    ui->lineEditMass->setValidator(val1);
    ui->lineEditLinearDamping->setValidator(val2);
    ui->lineEditAngularDamping->setValidator(val2);
    ui->lineEditFriction->setValidator(val3);
    ui->lineEditRestitution->setValidator(val3);
    physicsEnable(false);
}

WidgetNodePhysical::~WidgetNodePhysical()
{
    delete ui;
}

void WidgetNodePhysical::setupNode(const QString &name)
{
    _currentNode = Program::SceneNodeList[name];
    ui->comboBoxGeometry->clear();
    ui->listWidgetShape->clear();
    ui->checkBoxEnable->setCheckState(_currentNode->Physical.Enable ? Qt::Checked : Qt::Unchecked);
    ui->checkBoxStatic->setCheckState(_currentNode->Physical.Mass <= 0.0f ? Qt::Checked : Qt::Unchecked);
    ui->checkBoxTrigger->setCheckState(_currentNode->Physical.Trigger ? Qt::Checked : Qt::Unchecked);
    ui->lineEditMass->setText(QString::number(_currentNode->Physical.Mass));
    ui->lineEditLinearDamping->setText(QString::number(_currentNode->Physical.LinearDamping));
    ui->lineEditAngularDamping->setText(QString::number(_currentNode->Physical.AngularDamping));
    ui->lineEditFriction->setText(QString::number(_currentNode->Physical.Friction));
    ui->lineEditRestitution->setText(QString::number(_currentNode->Physical.Restitution));
    ui->checkBoxAllowSleep->setCheckState(_currentNode->Physical.AllowSleep ? Qt::Checked : Qt::Unchecked);
    QSet<QString> geometrySet;
    QMapIterator<QString, std::shared_ptr<EntitySceneNode>> iter(Program::SceneNodeList);
    while (iter.hasNext())
    {
        iter.next();
        const EntitySceneNode* sceneNode = iter.value().get();
        // 需要将碰撞几何体作为该场景节点的子节点，或者其自身是几何体
        if (sceneNode->Type == "geometry" && (sceneNode->Parent == _currentNode.get() || sceneNode == _currentNode.get()))
        {
            geometrySet.insert(sceneNode->Name);
            ui->comboBoxGeometry->addItem(sceneNode->Name);
        }
    }
    for (qsizetype i = 0; i < _currentNode->Physical.ShapeList.size();)
    {
        if (geometrySet.contains(_currentNode->Physical.ShapeList[i])) i++;
        else _currentNode->Physical.ShapeList.removeAt(i);
    }
    ui->listWidgetShape->addItems(_currentNode->Physical.ShapeList);
}

void WidgetNodePhysical::on_checkBoxEnable_checkStateChanged(const Qt::CheckState &state)
{
    _currentNode->Physical.Enable = state == Qt::Checked;
    physicsEnable(_currentNode->Physical.Enable);
}

void WidgetNodePhysical::on_checkBoxStatic_checkStateChanged(const Qt::CheckState &state)
{
    bool isStatic = state == Qt::Checked;
    if (isStatic) ui->lineEditMass->setText("0");
    ui->lineEditMass->setReadOnly(isStatic);
}

void WidgetNodePhysical::on_toolButtonAddShape_clicked()
{
    const QString geometryName = ui->comboBoxGeometry->currentText();
    if (!geometryName.isEmpty())
    {
        if (ui->listWidgetShape->findItems(geometryName, Qt::MatchExactly).count() > 0)
        {
            QMessageBox::warning(this, "错误", "请勿重复添加");
            return;
        }
        _currentNode->Physical.ShapeList.append(geometryName);
        ui->listWidgetShape->addItem(geometryName);
    }
}

void WidgetNodePhysical::on_toolButtonDelShape_clicked()
{
    QListWidgetItem* item = ui->listWidgetShape->currentItem();
    if (item)
    {
        _currentNode->Physical.ShapeList.removeOne(item->text());
        ui->listWidgetShape->removeItemWidget(item);
        delete item;
    }
}

void WidgetNodePhysical::on_pushButtonApply_clicked()
{
    _currentNode->Physical.Trigger = ui->checkBoxTrigger->checkState() == Qt::Checked;
    _currentNode->Physical.Mass = ui->lineEditMass->text().toFloat();
    _currentNode->Physical.LinearDamping =  ui->lineEditLinearDamping->text().toFloat();
    _currentNode->Physical.AngularDamping = ui->lineEditAngularDamping->text().toFloat();
    _currentNode->Physical.Friction = ui->lineEditFriction->text().toFloat();
    _currentNode->Physical.Restitution = ui->lineEditRestitution->text().toFloat();
    _currentNode->Physical.AllowSleep = ui->checkBoxAllowSleep->checkState() == Qt::Checked;
    if (!_currentNode->Physical.Enable)
    {
        AvatarLibrary::avatar_command(QString("physics.unbind('%1')").arg(_currentNode->Name));
        return;
    }
    if (_currentNode->Physical.ShapeList.isEmpty() && _currentNode->Physical.Mass > 0)
    {
        QMessageBox::warning(this, "错误", "非静态物体需绑定至少一个碰撞体");
        return;
    }
    AvatarLibrary::avatar_command(_currentNode->ScriptPhysical());
}

void WidgetNodePhysical::physicsEnable(bool enable)
{
    ui->checkBoxStatic->setEnabled(enable);
    ui->checkBoxTrigger->setEnabled(enable);
    ui->lineEditMass->setEnabled(enable);
    ui->lineEditLinearDamping->setEnabled(enable);
    ui->lineEditAngularDamping->setEnabled(enable);
    ui->lineEditFriction->setEnabled(enable);
    ui->lineEditRestitution->setEnabled(enable);
    ui->checkBoxAllowSleep->setEnabled(enable);
    ui->listWidgetShape->setEnabled(enable);
    ui->comboBoxGeometry->setEnabled(enable);
    ui->toolButtonAddShape->setEnabled(enable);
    ui->toolButtonDelShape->setEnabled(enable);
}
